﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Flatland.GeneticProgramming.CoreTypes;

/**
* 
* Copyright (c) 2012 Anders Høst Kjærgaard | ahkj@itu.dk
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, 
* including without limitation the rights to use, copy, modify, merge, publish, distribute, 
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Flatland.GeneticProgramming.SyntaxTree {
    [Serializable]
    public class Node : Tree {

        /// <summary>
        /// Get or set the children
        /// </summary>
        public List<Tree> Children { get; set; }

        /// <summary>
        /// Get or set the Function
        /// </summary>
        public Function Function { get; set; }

        private Node() { }

        /// <summary>
        /// Construct a Node
        /// </summary>
        /// <param name="function"></param>
        public Node(Function function) {
            Children = new List<Tree>();
            Function = function;
        }

        /// <summary>
        /// Execute the function held by this node
        /// </summary>
        /// <returns></returns>
        public override Object Execute(GenoType genoType) {
            switch (Function.SetType) {
                case SetType.FUNCTION: {
                        Object[] args = new object[Children.Count];
                        for (int i = 0; i < args.Length; i++) {
                            args[i] = Children[i].Execute(genoType);
                        }
                        return genoType.GetType().InvokeMember(Function.MethodInfo.Name, PrimitiveSet.BasicFlags | BindingFlags.InvokeMethod, null, genoType, args);
                    }

                case SetType.IF_THEN_ELSE: {
                        if ((bool)Children[0].Execute(genoType)) {
                            Children[1].Execute(genoType);
                        }
                        else
                            Children[2].Execute(genoType);
                    }
                    break;

                case SetType.SEQUENCE: {
                        Object[] args = new object[Children.Count];
                        for (int i = 0; i < args.Length; i++) {
                            args[i] = Children[i].Execute(genoType);
                        }
                    }
                    break;
            }
            return new object();
        }

        /// <summary>
        /// Replace a subTree.
        /// Does nothing if the child to be replaced does not exist
        /// </summary>
        /// <param name="t1">The Tree to be replaced</param>
        /// <param name="t2">The Tree to be inserted</param>
        public void Replace(Tree t1, Tree t2) {
            for (int i = 0; i < Children.Count; i++) {
                if (Children[i] == t1) {
                    Children[i] = t2;
                    Children[i].Parent = this;
                    break;
                }
            }
        }

        public override object Clone() {
            Node clone = new Node(Function);
            List<Tree> childClones = new List<Tree>(Children.Count);
            for (int i = 0; i < Children.Count; i++) {
                Tree child = (Tree)Children[i].Clone();
                child.Parent = clone;
                childClones.Add(child);
            }
            clone.Children = childClones;
            return clone;
        }

        public override bool  Equals(object obj){
            if (obj == null) return false;
            if (obj.GetType() == typeof(Node))
                return Function.Equals(((Node) obj).Function);
            if(obj.GetType() == typeof(Leaf))
                return Function.Equals(((Leaf) obj).Terminal);
            return false;
        }

        /// <summary>
        /// True if the node holds a command function
        /// </summary>
        /// <returns></returns>
        public override bool IsCommandSet() {
            return Function.IsCommandSet();
        }


        /// <summary>
        /// Overridden ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            string s = "Node ";
            if (Function.SetType == SetType.IF_THEN_ELSE)
                s += "IF_THEN_ELSE";
            else if (Function.SetType == SetType.SEQUENCE)
                s += "SEQUENCE";
            return s + " " + Function.MethodInfo + "Child count: " + Children.Count + " HashCode: " + GetHashCode();
        }
    }
}
